﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using ParserCombinatorLibrary;

namespace ParserConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            var calculator = new Calculator();
            while (true)
            {
                string input = Console.ReadLine();
                if (input == "") break;

                int firstError = 0;
                var tokens = calculator.Tokenize(input, out firstError);
                if (tokens != null)
                {
                    var result = calculator.Exp().Parse(tokens);
                    if (result != null)
                    {
                        Console.WriteLine(result.Result);
                        continue;
                    }
                }
                Console.WriteLine("The input is wrong.");
            }
        }
    }

    class Calculator : TokenizedGrammar<Calculator.TokenType>
    {
        public enum TokenType
        {
            Number,
            Add,
            Sub,
            Mul,
            Div,
            Open,
            Close,
            Space
        }

        public Calculator()
        {
            Define(TokenType.Number, @"\d+(\.\d+)?");
            Define(TokenType.Add, @"\+");
            Define(TokenType.Sub, @"-");
            Define(TokenType.Mul, @"\*");
            Define(TokenType.Div, @"/");
            Define(TokenType.Open, @"\(");
            Define(TokenType.Close, @"\)");
            Discard(TokenType.Space, @"\s+");
        }

        public Parser<double, Token<TokenType>> Factor()
        {
            return
                Or(
                from t in Tok(TokenType.Number)
                select double.Parse(t.Content),

                from _1 in Str("(")
                from e in Exp()
                from _2 in Str(")")
                select e,

                from _ in Str("+")
                from f in Factor()
                select f,

                from _ in Str("-")
                from f in Factor()
                select -f
                );
        }

        public Parser<double, Token<TokenType>> Term()
        {
            return
                from f in Factor()
                from remains in Any(Seq(Or(Str("*"), Str("/")), Factor()))
                select remains
                    .Aggregate(f, (a, b) => b.Item1.Content == "*" ? a * b.Item2 : a / b.Item2)
                    ;
        }

        public Parser<double, Token<TokenType>> Exp()
        {
            return
                from f in Term()
                from remains in Any(Seq(Or(Str("+"), Str("-")), Term()))
                select remains
                    .Aggregate(f, (a, b) => b.Item1.Content == "+" ? a + b.Item2 : a - b.Item2)
                    ;
        }
    }
}
